﻿using JMI_Nucleo.Classe;
using JMI_Nucleo.Enumerador;
using OR;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Reflection;

namespace JMI_Nucleo.JMIProvider
{
    public static class EngineBD
    {
        #region Variavel local
        private static string campoChave;
        private static DbConnection conexao;
        #endregion

        public static DbConnection Conectar()
        {
            BDUtil bdUtil = new BDUtil();
            conexao = bdUtil.ConexaoAtiva();
            return conexao; 
        }
        public static string CampoChave
        {
            get { return campoChave; }
            set { campoChave = value; }
        }

        public static DbConnection GetConexao
        {
            get
            {
                return conexao;
            }
        }

        #region Metodo public
        public static int GetID(string _Tabela, string _Campo, int _Empresa)
        {
            int retorno = 0;
            string cmdSQL = String.Empty;
            DbCommand cmd = null;
            object obj = null;
            bool parar = false;
            int novoID = 0;
            DbDataReader rd = null;

            try
            {
                do
                {
                    cmdSQL = "SELECT MAX(" + _Campo + ") AS PROX_ID FROM " + _Tabela +
                        " WHERE empresa = " + _Empresa.ToString();
                    cmd = conexao.CreateCommand();
                    cmd.CommandType = CommandType.Text;
                    cmd.Prepare();

                    obj = cmd.ExecuteScalar();

                    if (obj == DBNull.Value || Convert.ToInt32(obj) == 0)
                    {
                        retorno = 1;
                        parar = true;
                    }
                    else
                    {
                        novoID = Convert.ToInt32(obj);
                        novoID = novoID + 1;

                        cmdSQL = "SELECT " + _Campo + " FROM " + _Tabela +
                          " WHERE " + _Campo + " = " + novoID.ToString() + " AND empresa = " + _Empresa.ToString();

                        cmd = conexao.CreateCommand();
                        cmd.CommandType = CommandType.Text;
                        cmd.Prepare();
                        rd = cmd.ExecuteReader(CommandBehavior.Default);

                        if (rd.Read())
                            continue;
                        else
                        {
                            retorno = novoID;
                            parar = true;
                        }

                    }
                } while (parar == false);
            }
            catch (Exception ex)
            {
                #region Grava log local
                mLog _info = new mLog();
                _info._TipoErro = TipoErro.Erro;
                _info.Mensagem = "Erro ao recuperar ID.; " + ex.Message;
                _info.Metodo = "public static  int GetID(string _Tabela, string _Campo, int _Empresa)";
                _info.StackTrace = ex.StackTrace;
                _info.Tabela = String.Empty;
                LogLocal.Info = _info;
                LogLocal.Gravar();
                #endregion
            }
            finally
            {
                cmd.Dispose();
            }
            return retorno;
        }
        
        public static void Desconectar()
        {
            if (conexao != null && conexao.State == ConnectionState.Open)
                conexao.Close();
        }

        public static Object CriaParametro(DbCommand Comando, string NomeParametro, object ValorParametro)
        {
            DbParameter parametro = Comando.CreateParameter();
            //parametro.ParameterName = ":" + NomeParametro;
            parametro.ParameterName = NomeParametro;
            parametro.Value = ValorParametro;
            // Retorna o Parâmetro
            return parametro;
        }
        public static Object ExecutaComando(string comandoTexto, CommandType TipoComandoCriado, List<Object> ListaPametro, TipoComando EnumeradorTipoComando)
        {
            // Cria comando com os dados passado por parâmetro
            DbCommand cmd = CriaComando(comandoTexto, TipoComandoCriado, ListaPametro);

            // Cria objeto de retorno
            Object objRetorno = null;
            try
            {
                try
                {
                    switch (EnumeradorTipoComando)
                    {
                        case TipoComando.ExecuteNonQuery:
                            // Retorna o número de linhas afetadas
                            try
                            {
                                cmd.Prepare();
                                cmd.ExecuteNonQuery();
                            }
                            catch (Exception ex)
                            {
                                #region Grava log local
                                mLog _info = new mLog();
                                _info._TipoErro = TipoErro.Erro;
                                _info.Mensagem = "Erro ao finalizar transação de dados. " + ex.Message;
                                _info.Metodo = "public static  Object ExecutaComando(string comandoTexto, CommandType TipoComandoCriado, List<Object> ListaPametro, TipoComando EnumeradorTipoComando)";
                                _info.StackTrace = ex.StackTrace;
                                _info.Tabela = String.Empty;
                                LogLocal.Info = _info;
                                LogLocal.Gravar();
                                #endregion
                            }
                            break;
                        case TipoComando.ExecuteReader:
                            // Retorna um DbDataReader
                            objRetorno = cmd.ExecuteReader(CommandBehavior.CloseConnection);
                            break;
                        case TipoComando.ExecuteScalar:
                            // Retorna um objeto
                            objRetorno = cmd.ExecuteScalar();
                            break;
                        case TipoComando.ExecuteDataTable:
                            // Cria uma tabela
                            DataTable tabela = new DataTable();
                            // Executa o comando e salva os dados na tabela
                            DbDataReader rd = cmd.ExecuteReader();
                            tabela.Load(rd);
                            // Fecha o Reader
                            rd.Close();
                            objRetorno = tabela;
                            break;
                    }
                }
                catch (Exception ex)
                {
                    #region Grava log local
                    mLog _info = new mLog();
                    _info._TipoErro = TipoErro.Erro;
                    _info.Mensagem = "Erro ao executar comando: " + ex.Message;
                    _info.Metodo = "public static  Object ExecutaComando(string comandoTexto, CommandType TipoComandoCriado, List<Object> ListaPametro, TipoComando EnumeradorTipoComando)";
                    _info.StackTrace = ex.StackTrace;
                    _info.Tabela = String.Empty;
                    LogLocal.Info = _info;
                    LogLocal.Gravar();
                    #endregion
                }
            }
            finally
            {
                if (EnumeradorTipoComando != TipoComando.ExecuteReader)
                    cmd.Dispose();
            }
            return objRetorno;
        }
        
        public static void ExecuteNonQuery(string comandoSQL)
        {
            DbCommand cmd = conexao.CreateCommand();
            cmd.CommandType = CommandType.Text;
            cmd.CommandText = comandoSQL;
            try
            {
                cmd.ExecuteNonQuery();
            }
            catch (Exception ex)
            {
                #region Grava log local
                mLog _info = new mLog();
                _info._TipoErro = TipoErro.Erro;
                _info.Mensagem = "Erro ao finalizar transação de dados. " + ex.Message;
                _info.Metodo = "public static  void ExecuteNonQuery(string comandoSQL)";
                _info.StackTrace = ex.StackTrace;
                _info.Tabela = String.Empty;
                LogLocal.Info = _info;
                LogLocal.Gravar();
                #endregion
            }
        }
        public static void ExecuteNonQuery(string comandoSQL, Object[] arrParam)
        {
            DbCommand cmd;
            cmd = conexao.CreateCommand();
            cmd.CommandText = comandoSQL;
            cmd.Parameters.AddRange(arrParam);

            try
            {
                cmd.ExecuteNonQuery();
            }
            catch (Exception ex)
            {
                #region Grava log local
                mLog _info = new mLog();
                _info._TipoErro = TipoErro.Erro;
                _info.Mensagem = "Erro ao finalizar transação de dados. " + ex.Message;
                _info.Metodo = "public static  void ExecuteNonQuery(string comandoSQL, Object[] arrParam)";
                _info.StackTrace = ex.StackTrace;
                _info.Tabela = String.Empty;
                LogLocal.Info = _info;
                LogLocal.Gravar();
                #endregion
            }
        }
        public static void ExecuteEmBloco(string comandoSQL, bool UsaSequenciador = false)
        {
            DbTransaction trans = null;
            DbCommand cmd = conexao.CreateCommand();
            cmd.CommandType = CommandType.Text;
            cmd.CommandText = comandoSQL;

            try
            {
                trans = conexao.BeginTransaction(IsolationLevel.ReadCommitted);
                cmd.Connection = conexao;
                cmd.Transaction = trans;

                if (cmd.ExecuteNonQuery() != -1)
                    trans.Commit();
            }
            catch (Exception ex)
            {
                trans.Rollback();
                #region Grava log local
                mLog _info = new mLog();
                _info._TipoErro = TipoErro.Erro;
                _info.Mensagem = "Erro ao finalizar transação de dados. " + ex.Message;
                _info.Metodo = "public static  void ExecuteNonQuery(string comandoSQL)";
                _info.StackTrace = ex.StackTrace;
                _info.Tabela = String.Empty;
                LogLocal.Info = _info;
                LogLocal.Gravar();
                #endregion
            }
        }

        public static Object ExecuteDataReader(string sql)
        {
            DbDataReader rd = null;
            try
            {
                DbCommand cmd = conexao.CreateCommand();
                cmd.CommandType = CommandType.Text;
                cmd.CommandText = sql;
                rd = cmd.ExecuteReader(CommandBehavior.CloseConnection);
                return rd;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public static DbDataReader ExecuteDataReader(DbCommand cmd)
        {
            DbDataReader rd = null;
            try
            {
                rd = cmd.ExecuteReader(CommandBehavior.Default);
                return rd;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public static Object ExecuteDataReader(string sql, params Object[] arrParam)
        {
            DbDataReader reader;

            // Define o command
            DbCommand cmd = conexao.CreateCommand();
            cmd.CommandType = CommandType.Text;
            cmd.CommandText = sql;

            // trata os parametros
            if (arrParam != null)
            {
                foreach (DbParameter param in arrParam)
                    cmd.Parameters.Add(param);
            }

            try
            {
                // Executa o reader
                reader = cmd.ExecuteReader();
                return reader;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public static DbTransaction IniciaTransacao()
        {
            DbTransaction trans = null;

            try
            {
                trans = conexao.BeginTransaction(IsolationLevel.ReadCommitted);
            }
            catch (Exception ex)
            {
                trans.Rollback();
                #region Grava log local
                mLog _info = new mLog();
                _info._TipoErro = TipoErro.Erro;
                _info.Mensagem = "Erro ao inicializar transação de dados. " + ex.Message;
                _info.Metodo = "public static DbTransaction IniciaTransacao()";
                _info.StackTrace = ex.StackTrace;
                _info.Tabela = String.Empty;
                LogLocal.Info = _info;
                LogLocal.Gravar();
                #endregion
            }
            return trans;
        }
        
        public static bool FinalizaTransacao(DbTransaction Transacao, bool Sucesso)
        {
            bool _sucesso = false;
            try
            {
                if (Sucesso)
                {
                    Transacao.Commit();
                    _sucesso = true;
                }
            }
            catch (Exception ex)
            {
                Transacao.Rollback();
                #region Grava log local
                mLog _info = new mLog();
                _info._TipoErro = TipoErro.Erro;
                _info.Mensagem = "Erro ao finalizar transação de dados. " + ex.Message;
                _info.Metodo = "public static bool FinalizaTransacao(DbTransaction Transacao, bool Sucesso)";
                _info.StackTrace = ex.StackTrace;
                _info.Tabela = String.Empty;
                LogLocal.Info = _info;
                LogLocal.Gravar();
                #endregion
            }
            return _sucesso;
        }
        public static bool ExecuteNonQuery(DbCommand Comando)
        {
            bool _sucesso;
            try
            {
                _sucesso = Comando.ExecuteNonQuery() > 0;
            }
            catch (Exception ex)
            {
                _sucesso = false;
                #region Grava log local
                mLog _info = new mLog();
                _info._TipoErro = TipoErro.Erro;
                _info.Mensagem = "Erro ao finalizar transação de dados. " + ex.Message;
                _info.Metodo = "public static  void ExecuteNonQuery(Object Comando)";
                _info.StackTrace = ex.StackTrace;
                _info.Tabela = String.Empty;
                LogLocal.Info = _info;
                LogLocal.Gravar();
                #endregion
            }
            return _sucesso;
        }

        public static List<Object> GeraListaParametro<T>(DbCommand Comando, T InfoModelo, Boolean Flag = false)
        {
            string nomePropriedade;
            object valor;
            object _vlr = 0;

            List<Object> _lst = new List<Object>();
            Type tpModelo;
            tpModelo = InfoModelo.GetType();
            BindingFlags flagBinding = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Static;
            PropertyInfo[] arrPropriedade = tpModelo.GetProperties(flagBinding);

            foreach (PropertyInfo propriedade in arrPropriedade)
            {
                nomePropriedade = propriedade.Name.ToString().ToLower();
                // Quando o valor do parametro flag por "TRUE", então esta gerando uma lista de parâmetros para um comando UPDATE
                // Neste caso controla a chave primaria
                if (Flag)
                {
                    if (nomePropriedade.Equals("codigo"))
                    {
                        _vlr = propriedade.GetValue(InfoModelo, null);
                        continue;
                    }
                }
                valor = propriedade.GetValue(InfoModelo, null);
                _lst.Add(CriaParametro(Comando, nomePropriedade, valor));
            }

            if (Flag)
            {
                string sParametro = "PAR_" + CampoChave.ToUpper();
                _lst.Add(CriaParametro(Comando, sParametro, _vlr));
            }
            return _lst;
        }
   
        public static DbCommand CriaComando(string comandoTexto, CommandType TipoComandoCriado, List<Object> ListaPametro)
        {
            DbCommand comando = conexao.CreateCommand();
            comando.CommandText = comandoTexto;
            comando.CommandType = TipoComandoCriado;
            if (ListaPametro != null)
            {
                comando.Parameters.Clear();
                foreach (Object parametro in ListaPametro)
                {
                    comando.Parameters.Add(parametro);
                }
            }
            return comando;
        }

        public static List<DbParameter> GetValorParametro(DbCommand Comando, Modelo modelo)
        {
            string nomePropriedade;
            object valor;

            List<DbParameter> _lst = new List<DbParameter>();
            Type _modelo;
            _modelo = modelo.GetType();
            PropertyInfo[] arrPropriedade = _modelo.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (PropertyInfo propriedade in arrPropriedade)
            {
                nomePropriedade = propriedade.Name.ToString().ToLower();
                valor = propriedade.GetValue(modelo, null);
                _lst.Add(CriaParametro(Comando, nomePropriedade, valor) as DbParameter);
            }
            return _lst;
        }
        #endregion  
    }
}
